package com.unionftech.common.utils

import android.app.UiModeManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Rect
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Parcelable
import android.provider.OpenableColumns
import android.provider.Settings
import android.text.TextUtils
import android.util.TypedValue
import android.view.TouchDelegate
import android.view.View
import android.view.Window
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.widget.TextView
import androidx.core.widget.TextViewCompat
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.unionftech.common.CommonConstants
import com.unionftech.common.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import net.sourceforge.pinyin4j.PinyinHelper
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType
import skin.support.SkinCompatManager
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.io.Serializable
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.UUID
import java.util.regex.Pattern


object Utils {
    private const val DIFF: Long = 500
    private var lastClickTime: Long = 0
    private var lastButtonId = -1

    /**
     * 返回当前是不是暗黑模式
     */
    @JvmStatic
    fun isDarkModeEnable(context: Context): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
            uiModeManager.nightMode == UiModeManager.MODE_NIGHT_YES
        } else {
            false
        }
    }

    /**
     * 根据用户选择设置App的主题模式
     */
    @JvmStatic
    fun setThemes(context: Context) {
        val isFollowSystem =
            SpUtils.getInstance().getBoolean(CommonConstants.Key.KEY_FOLLOW_SYSTEM, false)
        val isDark = SpUtils.getInstance().getBoolean(CommonConstants.Key.KEY_IS_DARK_MODE, false)
        //获取当前系统的模式
        val darkModeEnable = isDarkModeEnable(context)
        if (isFollowSystem) {
            switchThemes(darkModeEnable)
        } else {
            switchThemes(isDark)
        }
    }

    /**
     * 更换主题模式
     */
    @JvmStatic
    fun switchThemes(isDark: Boolean) {
        if (isDark) {
            SkinCompatManager.getInstance()
                .loadSkin("night", SkinCompatManager.SKIN_LOADER_STRATEGY_BUILD_IN)// 后缀加载
        } else {
            SkinCompatManager.getInstance().restoreDefaultTheme()
        }
    }

    /**
     * 判断两次点击的间隔，如果小于1000，则认为是多次无效点击
     *
     * @return
     */
    @JvmStatic
    fun isFastDoubleClick(): Boolean {
        return isFastDoubleClick(-1, DIFF)
    }

    /**
     * 判断两次点击的间隔，如果小于1000，则认为是多次无效点击
     *
     * @return
     */
    @JvmStatic
    fun isFastDoubleClick(buttonId: Int): Boolean {
        return isFastDoubleClick(buttonId, DIFF)
    }

    /**
     * 判断两次点击的间隔，如果小于diff，则认为是多次无效点击
     *
     * @param diff
     * @return
     */
    @JvmStatic
    fun isFastDoubleClick(buttonId: Int, diff: Long): Boolean {
        val time = System.currentTimeMillis()
        val timeD = time - lastClickTime
        if (lastButtonId == buttonId && lastClickTime > 0 && timeD < diff) {
            return true
        }
        lastClickTime = time
        lastButtonId = buttonId
        return false
    }

    /**
     * 隐藏底部虚拟控制条
     */
    @JvmStatic
    fun setDialogNavigationBarTransparent(window: Window) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // Android 11+ 的新方法
            window.setDecorFitsSystemWindows(false)
            val controller = window.insetsController
            if (controller != null) {
                // 隐藏状态栏和导航栏
                controller.hide(WindowInsets.Type.navigationBars())
                // 设置沉浸式行为（滑动边缘临时显示）
                controller.systemBarsBehavior =
                    WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            }
        } else {
            // 旧版本兼容代码
            window.navigationBarColor = Color.TRANSPARENT
            @Suppress("deprecation") window.decorView.systemUiVisibility =
                (View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
        }
    }

    /**
     * 判断当前排版是不是RTL
     */
    @JvmStatic
    fun isRTL(): Boolean {
        val config: Configuration = Resources.getSystem().configuration
        return config.layoutDirection == View.LAYOUT_DIRECTION_RTL
    }

    /**
     * 获取App的versionCode
     */
    @JvmStatic
    fun getAppVersionCode(context: Context): Int {
        var versionCode = 0
        try {
            val packageInfo =
                context.applicationContext.packageManager.getPackageInfo(context.packageName, 0)
            versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                packageInfo.longVersionCode.toInt()
            } else {
                packageInfo.versionCode
            }
        } catch (e: Exception) {
            LogUtils.e("Utils", "getAppVersionCode error:${e.message}")
        }
        return versionCode
    }

    /**
     *  获取版本号名称
     */
    @JvmStatic
    fun getVersionName(context: Context): String {
        var verName = ""
        try {
            verName = context.packageManager.getPackageInfo(
                context.packageName, 0
            ).versionName
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return verName
    }

    @JvmStatic
    fun getAppName(context: Context): String {
        return try {
            val packageName = context.packageName
            val packageManager = context.packageManager
            val packageInfo =
                packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
            context.resources.getString(packageInfo.applicationInfo.labelRes)
        } catch (e: PackageManager.NameNotFoundException) {
            ""
        }
    }

    @JvmStatic
    fun compareVersions(version1: String, version2: String): Int {
        val v1 = version1.replace("V", "").split(".")
        val v2 = version2.replace("V", "").split(".")

        for (i in 0 until maxOf(v1.size, v2.size)) {
            val num1 = v1.getOrNull(i)?.toIntOrNull() ?: 0
            val num2 = v2.getOrNull(i)?.toIntOrNull() ?: 0

            when {
                num1 > num2 -> return 1
                num1 < num2 -> return -1
            }
        }
        return 0
    }

    /**
     * 判断当前网络是否可用(6.0以上版本)
     * 实时
     * @param context
     * @return
     */
    @JvmStatic
    fun isNetSystemUsable(context: Context): Boolean {
        var isNetUsable = false
        val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val networkCapabilities = manager.getNetworkCapabilities(manager.activeNetwork)
        if (networkCapabilities != null) {
            isNetUsable =
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
        }
        return isNetUsable
    }

    @JvmStatic
    fun uriToFile(context: Context, uri: Uri): File? {
        if (uri.scheme == ContentResolver.SCHEME_FILE) {
            return File(uri.path!!) // 文件 URI 直接转 File
        }
        if (uri.scheme != ContentResolver.SCHEME_CONTENT) {
            return null
        }
        val cursor = context.contentResolver.query(
            uri, null, null, null, null
        )
        cursor?.use {
            if (it.moveToFirst()) {
                val displayNameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                val fileName = it.getString(displayNameIndex)
                val cacheDir = context.cacheDir
                val file = File(cacheDir, fileName)
                try {
                    context.contentResolver.openInputStream(uri)?.use { inputStream ->
                        FileOutputStream(file).use { outputStream ->
                            inputStream.copyTo(outputStream)
                        }
                    }
                    return file
                } catch (e: Exception) {
                    e.printStackTrace()
                    return null
                }
            }
        }
        return null
    }

    /**
     * 判断当前的字符串中是否包含中文
     */
    @JvmStatic
    fun isContainChinese(str: String): Boolean {
        val pattern = Pattern.compile("[\u4e00-\u9fa5]")
        val matcher = pattern.matcher(str)
        return matcher.find()
    }

    /**
     * 将中文字符串转换成拼音
     */
    @JvmStatic
    fun convertToPinyin(str: String): String {
        if (TextUtils.isEmpty(str) || !isContainChinese(str)) {
            return ""
        }
        val format = HanyuPinyinOutputFormat()
        format.toneType = HanyuPinyinToneType.WITHOUT_TONE
        format.caseType = HanyuPinyinCaseType.LOWERCASE
        format.vCharType = HanyuPinyinVCharType.WITH_V
        val pinyinBuilder = StringBuilder()
        for (char in str) {
            if (!isContainChinese(char.toString())) {
                pinyinBuilder.append(char)
                continue
            }
            val array = PinyinHelper.toHanyuPinyinStringArray(char, format)
            if (array.isNullOrEmpty()) {
                pinyinBuilder.append(char)
                continue
            }
            array[0].forEachIndexed { index, char ->
                if (index == 0) {
                    pinyinBuilder.append(char.uppercase())
                } else {
                    pinyinBuilder.append(char)
                }
            }

        }
        return pinyinBuilder.toString()
    }

    @JvmStatic
    fun copyText(context: Context, str: String) {
        val clipboardManager =
            context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        val clipData = ClipData.newPlainText("", str)
        clipboardManager.setPrimaryClip(clipData)
    }


    /**
     * 消抖行为
     *
     */
    @JvmStatic
    fun debounceSuspend(
        delayMs: Long = 500L, coroutineScope: CoroutineScope, f: suspend CoroutineScope.() -> Unit
    ): () -> Unit {
        var job: Job? = null
        return {
            job?.cancel()
            job = coroutineScope.launch {
                delay(delayMs)
                job = null
                f()
            }
        }
    }

    /**
     * 主线程的消抖行为
     */
    @JvmStatic
    fun <T> debounceOnMainThread(delayMs: Long = 500L, callback: (T) -> Unit): (T) -> Unit {
        val handle = Handler(Looper.getMainLooper())
        var runnable: Runnable? = null
        return { t ->
            runnable?.let {
                handle.removeCallbacks(it)
            }
            runnable = Runnable {
                callback(t)
            }
            handle.postDelayed(runnable!!, delayMs)
        }
    }

    /**
     * 判断文件大小处于限制内
     */
    @JvmStatic
    fun checkFileSizeIsLimit(fileLen: Long, fileSize: Int, fileUnit: String): Boolean {
        var fileSizeCom = 0L
        if ("B" == fileUnit.uppercase()) {
            fileSizeCom = fileSize.toLong()
        } else if ("K" == fileUnit.uppercase()) {
            fileSizeCom = 1024 * fileSize.toLong()
        } else if ("M" == fileUnit.uppercase()) {
            fileSizeCom = 1024 * 1024 * fileSize.toLong()
        } else if ("G" == fileUnit.uppercase()) {
            fileSizeCom = 1024 * 1024 * 1024 * fileSize.toLong()
        }
        LogUtils.d("checkFileSizeIsLimit  fileLen->${fileLen}")
        LogUtils.d("checkFileSizeIsLimit  fileSizeCom->${fileSizeCom}")
        return fileLen > fileSizeCom
    }

    /**
     * 调转google商店应用详情页
     */
    @JvmStatic
    fun startGooglePlay(packageName: String, context: Context) {
        if (TextUtils.isEmpty(packageName)) {
            return
        }
        val intent = Intent(Intent.ACTION_VIEW)
        intent.setPackage("com.android.vending")
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.setData(Uri.parse("market://details?id=$packageName"))
        context.startActivity(intent)
    }

    /**
     * 获取设备ID
     */
    @JvmStatic
    fun generateUniqueId(context: Context): String {
        val androidId = Settings.Secure.getString(
            context.contentResolver, Settings.Secure.ANDROID_ID
        )
        // 如果 Android ID 不可用，则生成随机 UUID
        return if (androidId == "9774d56d682e549c") {
            UUID.randomUUID().toString()
        } else {
            androidId
        }
    }

    /**
     * 获取美化后的设备名称
     */
    @JvmStatic
    fun getPrettyDeviceName(): String {
        val manufacturer = Build.MANUFACTURER
        val model = Build.MODEL

        return when {
            model.startsWith(manufacturer, ignoreCase = true) -> model
            manufacturer.isBlank() -> model
            else -> "${manufacturer.replaceFirstChar { it.uppercase() }} $model"
        }
    }

}

/**
 * 扩展点击区域的范围
 * @param expendSize 需要扩展的尺寸（以sp为单位的）
 */
fun View.expandTouchArea(expendSize: Int = 20) {
    val parentView = parent as View
    parentView.post {
        val rect = Rect()
        getHitRect(rect)
        rect.left -= expendSize
        rect.top -= expendSize
        rect.right += expendSize
        rect.bottom += expendSize
        parentView.touchDelegate = TouchDelegate(rect, this)
    }
}

fun Double.formatAsMoney(): String {
    return DecimalFormat("#,##0.00", DecimalFormatSymbols(Locale.US)).apply {
        roundingMode = RoundingMode.HALF_UP
    }.format(this)
}

fun Int.formatAsMoney(): String {
    return DecimalFormat("#,##0.00", DecimalFormatSymbols(Locale.US)).apply {
        roundingMode = RoundingMode.HALF_UP
    }.format(this)
}

fun Long.formatAsMoney(): String {
    return DecimalFormat("#,##0.00", DecimalFormatSymbols(Locale.US)).apply {
        roundingMode = RoundingMode.HALF_UP
    }.format(this)
}

inline fun InputStream.copyTo(
    out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE, progress: (Long) -> Unit
): Long {
    var bytesCopied: Long = 0
    val buffer = ByteArray(bufferSize)
    var bytes = read(buffer)
    while (bytes >= 0) {
        out.write(buffer, 0, bytes)
        bytesCopied += bytes
        bytes = read(buffer)
        progress(bytesCopied)
    }
    return bytesCopied
}

/**
 * 倒计时
 */
inline fun FragmentActivity.countDown(
    intervalMillis: Long = 1000,//间隔
    time: Int = 3,
    crossinline start: (scope: CoroutineScope) -> Unit,
    crossinline end: () -> Unit,
    crossinline next: (time: Int) -> Unit,
    crossinline error: (msg: String?) -> Unit
) {
    lifecycleScope.launch {
        flow {
            (time downTo 1).forEach {
                kotlinx.coroutines.delay(intervalMillis)
                emit(it)
            }
        }.onStart {
            start(this@launch)
        }.onCompletion {
            end()
        }.catch {
            error(it.message ?: "countDown error")
        }.collect {
            next(it)
        }
    }
}

fun TextView.autoSize(autoSizeMinTextSize: Int, autoSizeMaxTextSize: Int) {
    TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
        this,
        autoSizeMinTextSize,
        autoSizeMaxTextSize,
        this.context.resources.getDimension(R.dimen.dp_2).toInt(),
        TypedValue.COMPLEX_UNIT_PX
    )
}


inline fun <reified T : Serializable> Bundle.serializable(key: String): T? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java)
    else -> @Suppress("DEPRECATION") getSerializable(key) as? T
}

inline fun <reified T : Serializable> Intent.serializable(key: String): T? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializableExtra(
        key, T::class.java
    )

    else -> @Suppress("DEPRECATION") getSerializableExtra(key) as? T
}

inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getParcelable(key, T::class.java)
    else -> @Suppress("DEPRECATION") getParcelable(key) as? T
}

inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getParcelableExtra(key, T::class.java)
    else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T
}

// 扩展函数
fun Calendar.formatToDateString(): String {
    return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(this.time)
}

